﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;

namespace MetMax.BusinessObject
{
    public class Base
    {
        private static Options _opt;
        public Options opt
        {
            get { return _opt; }
            set { _opt = value; }
        }

        #region constructors
        public Base(Options option)
        {
            opt = option;
        }

        public Base(Base other)
            : this(other.opt)
        {
            name = other.name;
            ri = other.ri;
            mass = other.mass;
            area = other.area;
            rt1 = other.rt1;
            rt2 = other.rt2;
            spectrum = other.spectrum;

            Concentration = other.Concentration;
            Conc_Units = other.Conc_Units;
            Match = other.Match;
            Quant_SN = other.Quant_SN;
            Reverse = other.Reverse;
            Type = other.Type;
        }
        #endregion constructors

        public string name { get; set; } //metabolite
        public float? ri { get; set; } //retention index
        private string _mass;
        public string mass
        {
            get
            {
                return _mass;
            }
            set
            {
                _mass = value;
                float? hlpMass = Importer.Base.ToFloat(value);
                if (hlpMass.HasValue)
                {
                    massValue = hlpMass.Value;
                }
                else
                {
                    massValue = float.NaN;
                }
            }
        }
        public float? area { get; set; }
        public float? rt1 { get; set; } //1st Dimension Time (s)
        public float? rt2 { get; set; } //2nd Dimension Time (s)
        public udtMassSpectra spectrum { get; set; }

        public float? Concentration { get; set; }
        public string Conc_Units { get; set; }
        public int? Match { get; set; }
        public float? Quant_SN { get; set; }
        public int? Reverse { get; set; }
        public string Type { get; set; }

        /// <summary>
        /// returns the retention time of the secon column under consideration of possible wraparounds
        /// </summary>
        /// <param name="opt"></param>
        /// <returns></returns>
        public float? rt2wrapped
        {
            get
            {
                if (!rt2.HasValue)
                {
                    return null;
                }

                return WrapArounds * opt.secondDimensionLength + rt2;
            }
        }

        /// <summary>
        /// if this is a alcane (name = #c10) then the name is evalueated to a retenetion index
        /// </summary>
        /// <param name="opt"></param>
        /// <returns></returns>
        public int? riAlkan
        {
            get
            {
                Match m = r.Match(this.name);
                if (m.Groups["alkane"].Success)
                {
                    return int.Parse(m.Groups["alkane"].Value) * 100; //'#c10' ==> 1000
                }
                else
                {
                    return null;
                }
            }
        }

        /// <summary>
        /// if this is a fame (name = #fame12) then the name is evalueated to a retenetion index
        /// </summary>
        /// <param name="opt"></param>
        /// <returns></returns>
        public int? riFame
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        /// <summary>
        /// returns the number of wrap arounds of this peak based on the given list of wraparounds
        /// </summary>
        /// <param name="opt"></param>
        /// <returns></returns>
        public int WrapArounds
        {
            get
            {
                int wrap = 0;
                Dictionary<string, int> wraps = opt.wrapArounds.ToDictionary(w => w.name, w => w.wraps);

                if (!wraps.TryGetValue(name, out wrap))
                {
                    if (rt2.Value < opt.ColumnDeadTime)
                    {
                        wrap = 1;
                    }
                }
                return wrap;
            }
        }

        /// <summary>
        /// removes all trailing decimals from the end of the name
        /// </summary>
        public string nameWiped
        {
            get
            {
                return Regex.Replace(name, @":[0-9]*$", string.Empty);
            }

        }

        public string GetName
        {
            get
            {
                return opt.wipeTrailingDecimals ? nameWiped : name;
            }
        }

        /// <summary>
        /// this regular expression is used to extract alcanes #c10 for exmple or fatty acids #f32
        /// </summary>
        private static Regex r = new Regex(@"^(#c(?<alkane>\d+))|(#f(?<fame>\d+))$", RegexOptions.Compiled);
        /// <summary>
        /// retrun the Match of the name against the regular expression to extract potential Retention Index (RI) markers
        /// </summary>
        public Match RiMarkerRegExMatch
        {
            get
            {
                return r.Match(name);
            }
        }

        /// <summary>
        /// returns the intensity of a peak given by the mass from the spectrum
        /// </summary>
        public float? IntensityOfMass
        {
            get
            {
                if (spectrum == null || float.IsNaN(massValue) || !spectrum.containsPeak(massValue))
                {
                    return null;
                }
                return spectrum[massValue];
            }
        }

        public object ValueNeeded()
        {
            switch (Properties.Settings.Default.myOptions.exportFact)
            {
                case DisplayProperties.area:
                    return area;
                case DisplayProperties.IntensityOfMass:
                    return IntensityOfMass;
                case DisplayProperties.firstDimensionRt:
                    return rt1;
                case DisplayProperties.secondDimensionRt:
                    return rt2;
                case DisplayProperties.secondDimensionRtWrapped:
                    return rt2wrapped;
                case DisplayProperties.spectrum:
                    return spectrum;
                case DisplayProperties.name:
                    return name;
                case DisplayProperties.Concentration:
                    return Concentration;
                case DisplayProperties.Conc_Units:
                    return Conc_Units;
                case DisplayProperties.Match:
                    return Match;
                case DisplayProperties.Quant_SN:
                    return Quant_SN;
                case DisplayProperties.Reverse:
                    return Reverse;
                case DisplayProperties.Type:
                    return Type;
                default:
                    return "not supported";
            }
        }

        public float massValue { get; private set; }
    }

    public class BusinessObject_rt2wrapped_EqualityComparer : IEqualityComparer<Base>
    {
        #region IEqualityComparer<BusinessObject> Members

        public bool Equals(Base x, Base y)
        {
            return (x.rt2wrapped == y.rt2wrapped);
        }

        public int GetHashCode(Base obj)
        {
            return obj.rt2wrapped.GetHashCode();
        }

        #endregion
    }
}
